Portfólio

Carregando pacotes

#install.packages('ggplot2', dependencies=TRUE, repos='http://cran.r-project.org')
#
#install.packages("lubridate")
#
#install.packages('plotly')
#
#install.packages('dplyr')
#
#install.packages('leaflet')
#
#install.packages('corrplot')
#install.packages('readxl')
library(ggplot2)
library(leaflet)
library(dplyr)
library(plotly)
library(lubridate)
library(corrplot)
library(readxl)

Conceitos de variáveis

Vetor

Toda variável no R é um vetor, um vetor pode visto como um conjunto de valores linear e homogêneo.

Para atribuir um valor à uma variável, utilizamos a seta <- indicando para onde estamos direcionando o valor.

É importante saber também, que para criar um vetor com valores, podemos utilizar a função c() que combina os valores em um vetor

Sendo assim, abaixo estamos criando a variável vetor e atribuindo o valor 1 5 4

vetor <- c(1, 5, 4)
vetor
[1] 1 5 4

Tipos de valores

Numéricos e Caracteres

No R tempos o conceito de tipos, onde cada valor tem um tipo específico, lembra das aulas de matemática sobre inteiros, decimais, etc?

Para verificar o tipo interpretado pelo R de um valor, podemos utilizar a função class(valor), onde valor é igual ao valor que você quer verificar.

class(5)
[1] "numeric"
class("Olá mundo")
[1] "character"

Reconhecendo tipos de variáveis

Veja que o R reconheceu o valor 5 como númerico e o texto “Olá mundo” como um conjunto de caracteres.

Isto também se aplica a variáveis, veja só:

variavel_numerica <- c(1,5,4,7)
variavel_caracteres <- c("Olá mundo")
class(variavel_numerica)
[1] "numeric"
class(variavel_caracteres)
[1] "character"

Também podemos usar as funções disponíveis em “is” para verificar os tipos, essa verificação retorna um tipo lógico para nós

variavel <- "5"
is.numeric(variavel)
[1] FALSE
is.character(variavel)
[1] TRUE

Lógicos

No R, também é possível criar tipos lógicos (verdadeiro ou falso)

logicos <- c(TRUE, FALSE, TRUE)
logicos2 <- c(T, F, T)
logicos
[1]  TRUE FALSE  TRUE
logicos2
[1]  TRUE FALSE  TRUE
class(logicos)
[1] "logical"

Veja que é possível abreviar as declarações.

Inteiros Explicitos

Você deve ter percebido que no caso do tipo numérico, o tipo não foi declarado explicitamente como inteiro, para fazer isso veja o próximo trecho:

inteiros <- c(1L, 2L, 3L)
inteiros
[1] 1 2 3
class(inteiros)
[1] "integer"

Gerando sequências

Gerar sequências no R é uma coisa muito fácil e divertida! Temos algumas formas para fazer isso:

#Gerando números de 1 a 10
1:10
 [1]  1  2  3  4  5  6  7  8  9 10
#Gerando números de 10 a 1
10:1
 [1] 10  9  8  7  6  5  4  3  2  1
#Gerando números de 100 a 120
seq(100, 120)
 [1] 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
#Gerando 10 números a partir de 100
seq(100, length.out = 10)
 [1] 100 101 102 103 104 105 106 107 108 109
#Gerando números de 10 a 20 de 2 em 2
seq.int(from = 10, to = 20, by = 2)
[1] 10 12 14 16 18 20
#Gerando 20 números
seq_len(20)
 [1]  1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
#Gerando um vetor do mesmo tamanho que o vetor passado
seq_along(c(70, 2))
[1] 1 2
#Repetindo o número 4 5 vezes
rep(4, times = 5)
[1] 4 4 4 4 4

NA, NaN, Inf, -Inf e NULL

Os tipos especiais são valores que possuem uma característica bem específica.

NA = Não disponível (Not Available) NaN = Não númerico (Not A Number) Inf = Infinito -Inf = -Infinito NULL = Vazio

Perceba que NA possui um tipo, mas NULL não, NULL representa o nada no caso do R e de diversas linguagens de programação.

Um detalhe é que não é possível colocar NULL em um vetor, ou seja, caso criemos um vetor com NULL, o R remove ele automáticamente

valor.na <- NA
valor.null <- NULL
valor.infinito <- Inf;
valor.menos.infinito <- -Inf
valor.nan <- NaN
vetor.com.null <- c(10,10,10,NULL)
vetor.com.null
[1] 10 10 10

Operações aritméticas

No R é possível fazer operações aritméticas entre os valores disponíveis, abaixo teremos exemplos para algumas operações aritméticas simples:

# Adição
adicao <- 5+5
adicao
[1] 10
# Subtração
subtracao <- 5-5
subtracao
[1] 0
# Multiplicação
multiplicao <- 5*5
multiplicao
[1] 25
# Divisão
divisao <- 5/5
divisao
[1] 1
#Raiz Quadrada
raiz <- sqrt(10)
raiz
[1] 3.162278
#Numero imaginário
numero <- 1i
numero
[1] 0+1i

Operações com vetores

As operações aritméticas se estendem a vetores também, veja abaixo um exemplo:

# Vetor de dez posições
vetor <- c(1:10)
vetor * 2
 [1]  2  4  6  8 10 12 14 16 18 20
# Veja que obtemos o dobro de cada valor do vetor, isso se aplica para todas as operações.

Tipos avançados

Fatores

Através de fatores, é possível classificar dados para que as máquinas consigam processar com mais facilidade. Veja que no output, o R escreve “Levels: Feminino Masculino” para identificar as classes encontradas.

sexo <- c("Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino","Feminino", "Masculino")
fatorado <- as.factor(sexo);
fatorado
 [1] Feminino  Masculino Feminino  Masculino Feminino  Masculino Feminino  Masculino Feminino  Masculino
Levels: Feminino Masculino

Listas

No R, temos o tipo de lista onde é possível armazenar vetores com tipos diferentes:

v1 <- c(1, 2, 3);
v2 <- c(T, F, T);
v3 <- c("a", "b", "c");
lista <- list(v1, v2, v3)
class(lista)
[1] "list"
lista
[[1]]
[1] 1 2 3

[[2]]
[1]  TRUE FALSE  TRUE

[[3]]
[1] "a" "b" "c"

Matrizes

Matrizes são um conjunto de valores distribuídos em linhas e colunas. A visualização abaixo deve esclarecer melhor:

matriz <- matrix(ncol = 5, nrow = 5, data = 1:5)
matriz
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    2    2    2    2    2
[3,]    3    3    3    3    3
[4,]    4    4    4    4    4
[5,]    5    5    5    5    5

Você deve ter percebido que também é possível atribuir uma matriz para uma variável com esse exemplo.

Vamos a um exemplo de operação com matrizes

matrizA <- matrix(ncol = 5, nrow = 5, data = 1:5)
matrizB <- matrix(ncol = 5, nrow = 5, data = 1:5)
# Esta operação abaixo não é uma multiplicação de matrizes, é apenas uma multiplicação de valores.
matriz <- matrizA * matrizB
matriz
     [,1] [,2] [,3] [,4] [,5]
[1,]    1    1    1    1    1
[2,]    4    4    4    4    4
[3,]    9    9    9    9    9
[4,]   16   16   16   16   16
[5,]   25   25   25   25   25

Para fazermos uma multiplicaçáo de matrizes, precisamos seguir uma regra: a quantidade de colunas da matriz A deve ser equivalente a quantidade de linhas da matriz B.

Abaixo um exemplo de multiplicação de matrizes:

linhas <- 5
colunas <- 10
matrizA <- matrix(ncol = linhas, nrow = colunas, data = 1:2)
matrizB <- matrix(ncol = colunas, nrow = linhas, data = 1:2)
matrizA %*% matrizB
      [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9] [,10]
 [1,]    7    8    7    8    7    8    7    8    7     8
 [2,]   14   16   14   16   14   16   14   16   14    16
 [3,]    7    8    7    8    7    8    7    8    7     8
 [4,]   14   16   14   16   14   16   14   16   14    16
 [5,]    7    8    7    8    7    8    7    8    7     8
 [6,]   14   16   14   16   14   16   14   16   14    16
 [7,]    7    8    7    8    7    8    7    8    7     8
 [8,]   14   16   14   16   14   16   14   16   14    16
 [9,]    7    8    7    8    7    8    7    8    7     8
[10,]   14   16   14   16   14   16   14   16   14    16

Funções úteis para matrizes

matrizA <- matrix(ncol = 2, nrow = 2, data = 1:4)
print("Dimensões da matriz - Linhas x Colunas")
[1] "Dimensões da matriz - Linhas x Colunas"
dim(matrizA)  #inversa, esta deve ser quadrada
[1] 2 2
print("Transposta")
[1] "Transposta"
t(matrizA) #transposta
     [,1] [,2]
[1,]    1    2
[2,]    3    4
print("Identidade")
[1] "Identidade"
diag(matrizA) #identidade
[1] 1 4
print("Inversa")
[1] "Inversa"
solve(matrizA)  #inversa, esta deve ser quadrada
     [,1] [,2]
[1,]   -2  1.5
[2,]    1 -0.5
matrizA <- cbind(matrizA, c(5,2)) #Adiciona colunas no fim da matriz
#Colunas adicionadas
print("Colunas adicionadas")
[1] "Colunas adicionadas"
matrizA
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    2
print("Linhas adicionadas")
[1] "Linhas adicionadas"
matrizA <- rbind(matrizA, c(5,2, 3))
matrizA
     [,1] [,2] [,3]
[1,]    1    3    5
[2,]    2    4    2
[3,]    5    2    3

Data Frame

Criar um dataframe é bem simples, veja:

vetorA <- c(1,5,4,7)
vetorB <- c("Olá mundo")
dataframe <- data.frame(vetorA, vetorB)
# Colocando nomes nas colunas
colnames(dataframe) <- c("Numérico", "Texto")
dataframe

O mais legal do dataframe, é que conseguimos colocar dados heterogêneos, ao contrário dos vetores e matrizes.

Também é possível criar um dataframe a partir de uma lista:

lista <- list(c(1,2), c(T,F), c("teste", "teste2"))
dataframe <- data.frame(lista)
dataframe

Datas

Geralmente o trabalho com datas é uma das coisas mais complexas em programação. Vamos ver aqui algumas funções que o R disponibiliza para nós:

data.texto = "13/11/2018 T 19:10:00"
data.date = as.Date(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time1 = as.POSIXct(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time2 = as.POSIXlt(data.texto,format="%d/%m/%Y T %H:%M:%S",tz="America/Sao_Paulo")
data.time1
[1] "2018-11-13 19:10:00 -02"
data.time2
[1] "2018-11-13 19:10:00 -02"
data.date 
[1] "2018-11-13"

Através do método unclass, podemos ver o conteúdo real de uma variável, suas propriedades e etc. Quando passamos data.date para a função unclass, obtemos a quantidade de dias desde 01/01/1970 até a data da variável.

unclass(data.date)
[1] 17848

No caso de time1 e time2 veja que não temos diferenças no texto, entretanto veja quando fazemos o unclass.

print("Time1")
[1] "Time1"
unclass(data.time1)
[1] 1542143400
attr(,"tzone")
[1] "America/Sao_Paulo"
print("Time2")
[1] "Time2"
unclass(data.time2)
$`sec`
[1] 0

$min
[1] 10

$hour
[1] 19

$mday
[1] 13

$mon
[1] 10

$year
[1] 118

$wday
[1] 2

$yday
[1] 316

$isdst
[1] 1

$zone
[1] "-02"

$gmtoff
[1] NA

attr(,"tzone")
[1] "America/Sao_Paulo"

O unclass no time1 retorna a contagem em segundos desde 01/01/1970 até a data da variável!!

Para obter a data atual

Sys.Date()
[1] "2018-12-19"

Lubridate

Lubridate é um pacote disponibilizado para manipular datas no R. Para instalar e carregar:

#install.packages("lubridate")
#library(lubridate)

O lubridate fornece funções que retornarão a data no formato solicitado e além disso ele trabalha com o conceito de duração.

segundos  = dseconds(260)
minutos  = dminutes(260)
anos  = dyears(260)
duration(10, units = "seconds")
[1] "10s"
segundos
[1] "260s (~4.33 minutes)"
minutos
[1] "15600s (~4.33 hours)"
anos
[1] "8199360000s (~259.82 years)"
#abaixo as funções de data
#Ano mes dia
data <- ymd("20190101")
# Dia mes ano hora
dmy_h("1110201810")
[1] "2018-10-11 10:00:00 UTC"
# Retorna o dia da semana
wday(data, label = T)
[1] Tue
Levels: Sun < Mon < Tue < Wed < Thu < Fri < Sat

Estruturas de controle

Para tomar algumas decisões durante a execução de código, o R fornece algumas estruturas de controle.

souBonito <- TRUE
if (souBonito) {
  print("Eu Sei")
} else {
  print("Vish")
}
[1] "Eu Sei"
souBonito <- F
ifelse(souBonito, "verdade", "falso")
[1] "falso"

Estruturas de controle são muito úteis quando você precisa testar algum tipo de condição, se alguma compra foi realizada por exemplo, ou se algo ocorreu.

Estruturas de repetição = loops

Loops são utilizados quando precisamos por exemplo repetir um conjunto de instruções para determinados itens.

itens <- c(10,20,30)
for (variable in itens) {
  print(variable)
}
[1] 10
[1] 20
[1] 30

Veja que escrevemos todos os itens do vetor na tela, podemos utilizar para consolidar informações e enfim, para qualquer conjunto de instruções que precise se repetir.

Vamos montar um dataframe com um loop

vetor <- 1:10
acumulado <- 0
tabela <- data.frame();
for (variable in vetor) {
  acumulado <- variable + acumulado
   tabela <- rbind(tabela, c(variable, acumulado))
}
colnames(tabela) <- c("Valor1", "Acumulado")
tabela

Funções

Funções são utilizadas quando queremos reaproveitar algum trecho de código específico. por exemplo, digamos que precisamos calcular o enesimo termo de uma Progressão Aritmética

primeiro.termo <- 1
razao <- 2
obter.termo.pa <- function(primeiro.termo, numero.termo, razao) {
  return(primeiro.termo + (numero.termo - 1) * razao)
}
obter.termo.pa(primeiro.termo, 50, razao)
[1] 99

Em funções, podemos receber reticências como parametro, que significa que podemos receber N parametros na função. Um exemplo de função assim é a função paste.

concatena <- function(...) {
  c <- paste(...)
  c
}
concatena("Sergio", "Prates")
[1] "Sergio Prates"

Amostras

No R possuimos a função sample para randomizar a ocorrência de determinados valores

# Letras de a até g
amostra1 <- letters[1:7]
# Letras de A até D
amostra2 <- LETTERS[1:4]
# Pode repetir as ocorrências
sample(x = amostra1, size = 20, replace = T)
 [1] "c" "f" "e" "e" "g" "g" "b" "g" "d" "d" "c" "g" "a" "b" "e" "a" "f" "f" "b" "a"
# Não pode repetir as ocorrências
sample(x = amostra2, size = 3,  replace = F)
[1] "C" "B" "D"

Para garantir que sempre o mesmo resultado aconteça, podemos utilizar a função set.seed com um valor fixo

set.seed(1)
sample(x = amostra1, size = 20, replace = T)
 [1] "b" "c" "e" "g" "b" "g" "g" "e" "e" "a" "b" "b" "e" "c" "f" "d" "f" "g" "c" "f"

Simulações

O R nos fornece alguns comandos para gerar dados aleatórios, sendo eles da família normal, binomial e uniforme.

Os comandos da familia normal possuem norm no final, os binomiais possuem binom e assim por diante… Veja abaixo exemplos:

set.seed(18) #garantindo que sempre sairá o mesmo resultado
# sd representa o desvio padrão dos dados
rnorm(n=10, mean=0, sd=1)
 [1]  0.92645924  1.82282117 -1.61056690 -0.28510975 -0.34207303  0.36617615 -1.32704085  2.41259221  0.06381535  1.54551478
dnorm(x = 1:10, mean = 0, sd = 1)
 [1] 2.419707e-01 5.399097e-02 4.431848e-03 1.338302e-04 1.486720e-06 6.075883e-09 9.134720e-12 5.052271e-15 1.027977e-18 7.694599e-23
pnorm( q = 1:10, mean = 0, sd = 1)
 [1] 0.8413447 0.9772499 0.9986501 0.9999683 0.9999997 1.0000000 1.0000000 1.0000000 1.0000000 1.0000000
rbinom(size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1), n = 10)
 [1]  0  0  1  1  0  1  7  8  9 10
dbinom(size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1), x = 1:10)
 [1] 1e-01 1e-02 1e-03 1e-04 1e-05 1e-06 1e+00 1e+00 1e+00 1e+00
pbinom(q = 1:10, size = 1:10, prob = c(0.1,0.1,0.1,0.1,0.1,0.1,1,1,1,1))
 [1] 1 1 1 1 1 1 1 1 1 1
rpois(100, 5)
  [1]  5  5  3  4  8  5  3  3  3  6  8  5  6  5  2  2  7  1  3  5  3  3  6  6  1  4  3  7  5  5  4  2  1  3  3  6  5 12  6  7  8  4  2 10  7  4  6
 [48]  5  2  3  6  5  7  5  6  6 11  5  6  7  7  4  5  3  6  6  7  4  2  6  4  6  4  6  3  4  3  7  6 13  4  3  5  3  1  4  3  5  8  8  5  6  6  6
 [95]  3  6  5  3  2  1

Resumo do dataset com Glimpse

Glimpse é uma função que está dentro do pacote dplyr. É muito interessante por que conseguimos ver um resumo dos dados e amostras. Veja abaixo para ficar mais claro o glimpse com o dataset do mtcars

glimpse(mtcars)
Observations: 32
Variables: 11
$ mpg  <dbl> 21.0, 21.0, 22.8, 21.4, 18.7, 18.1, 14.3, 24.4, 22.8, 19.2, 17.8, 16.4, 17.3, 15.2, 10.4, 10.4, 14.7, 32.4, 30.4, 33.9, 21.5, 15...
$ cyl  <dbl> 6, 6, 4, 6, 8, 6, 8, 4, 4, 6, 6, 8, 8, 8, 8, 8, 8, 4, 4, 4, 4, 8, 8, 8, 8, 4, 4, 4, 8, 6, 8, 4
$ disp <dbl> 160.0, 160.0, 108.0, 258.0, 360.0, 225.0, 360.0, 146.7, 140.8, 167.6, 167.6, 275.8, 275.8, 275.8, 472.0, 460.0, 440.0, 78.7, 75....
$ hp   <dbl> 110, 110, 93, 110, 175, 105, 245, 62, 95, 123, 123, 180, 180, 180, 205, 215, 230, 66, 52, 65, 97, 150, 150, 245, 175, 66, 91, 11...
$ drat <dbl> 3.90, 3.90, 3.85, 3.08, 3.15, 2.76, 3.21, 3.69, 3.92, 3.92, 3.92, 3.07, 3.07, 3.07, 2.93, 3.00, 3.23, 4.08, 4.93, 4.22, 3.70, 2....
$ wt   <dbl> 2.620, 2.875, 2.320, 3.215, 3.440, 3.460, 3.570, 3.190, 3.150, 3.440, 3.440, 4.070, 3.730, 3.780, 5.250, 5.424, 5.345, 2.200, 1....
$ qsec <dbl> 16.46, 17.02, 18.61, 19.44, 17.02, 20.22, 15.84, 20.00, 22.90, 18.30, 18.90, 17.40, 17.60, 18.00, 17.98, 17.82, 17.42, 19.47, 18...
$ vs   <dbl> 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1
$ am   <dbl> 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1
$ gear <dbl> 4, 4, 4, 3, 3, 3, 3, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 4, 4, 4, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 4
$ carb <dbl> 4, 4, 1, 1, 2, 1, 4, 2, 2, 4, 4, 3, 3, 3, 4, 4, 4, 1, 2, 1, 1, 2, 2, 4, 2, 1, 2, 2, 4, 6, 8, 2

Plots básico

Para fazer plots, ou gráficos em R podemos utilizar a função plot()

plot(x = cars$speed, y = cars$dist, type = "p", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "l", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

#Histogramas servem para analisar frequências
plot(x = cars$speed, y = cars$dist, type = "h", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "b", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "o", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

plot(x = cars$speed, y = cars$dist, type = "s", xlab = "Velocidade", ylab = "Distância", main = "Distância x Velocidade")

#Analisar correlação
#Tendencia
#Distribuição
#Box plot é um summary em gráficos
boxplot(airquality)

boxplot(airquality$Ozone, outline = F)

Usando outra biblioteca…

Podemos utilizar a equação abaixo para plotar um gráfico linear \(y = \beta_0 + \beta_1 + \epsilon\)

Onde

\(\beta_0 = 0,5\)

\(\beta_1 = 2,0\)

\(x\sim N(0;1²)\)

\(\epsilon\sim N(0;2²)\)

#install.packages('plotly')
#library(plotly)
set.seed(5)
x = rnorm(n=350, mean=0, sd=1)
e = rnorm(n=350, mean=0, sd=2)
y=0.5 + 2*x + e
plot(x=x, y=y)

plot_ly(x=x, y=y, type="scatter", mode="markers")

Gerando gráfico com pontos e linhas

airquality %>% filter(Month == 5 & !is.na(Ozone)) %>% arrange(Ozone) %>% select(Ozonio = Ozone) -> ozonio
ozonio %>% summary() %>% as.list() -> valores
plot(ozonio$Ozonio)
minimo <- min(teste$Ozonio)
maximo <- max(teste$Ozonio)
media <- mean(teste$Ozonio)
mediana <- median(teste$Ozonio)
quartil <- quantile(teste$Ozonio)
lines(c(0, 30), c(minimo, minimo), col = 'blue')
lines(c(0, 30), c(maximo, maximo), col = 'blue')
lines(c(0, 30), c(media, media), col = 'blue')
lines(c(0, 30), c(mediana, mediana), col = 'red')
lines(c(0, 30), c(11.00, 11.00), col = 'blue')

Baixando dados externos

Com a função download file podemos baixar arquivos da web, neste caso ele sempre trata como texto os dados.

baixar <- function(url) {
  
  #Cria a pasta caso não exista
  
  if(!file.exists('data')){
    dir.create('data')
  }
  
  file.url = url
  file.local = file.path('./data', basename(file.url))
  download.file(url = file.url, destfile = file.local , mode='wb')
}
baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas.csv')
trying URL 'https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas.csv'
Content type 'text/plain; charset=utf-8' length 1412 bytes
downloaded 1412 bytes
baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Partidas.csv')
trying URL 'https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Partidas.csv'
Content type 'text/plain; charset=utf-8' length 239003 bytes (233 KB)
downloaded 233 KB
baixar('https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Jogadores.csv')
trying URL 'https://raw.githubusercontent.com/elthonf/fiap-mba-r/master/data/Copas-Jogadores.csv'
Content type 'text/plain; charset=utf-8' length 2150588 bytes (2.1 MB)
downloaded 2.1 MB
baixar('https://github.com/elthonf/fiap-mba-r/raw/master/data/cameras.baltimore.xlsx')
trying URL 'https://github.com/elthonf/fiap-mba-r/raw/master/data/cameras.baltimore.xlsx'
Content type 'application/octet-stream' length 15453 bytes (15 KB)
downloaded 15 KB

Lendo dados de csv’s

Para ler dados de csvs podemos utilizar a função read.csv

copas <- read.csv('./data/Copas.csv', header = T)
copas

Para ler dados do excel, podemos utilizar o pacote

df.cameras <- read_xlsx('./data/cameras.baltimore.xlsx')
head(df.cameras)

Manipulando estruturas de tabelas com dplyr

O pacote dplyr nos ajuda a manipular estruturas de tabelas de maneira bastante eficiente.

Abaixo utilizamos o pipe para passar o conteúdo

BrFlights2 <- read.csv('./data/BrFlights2.csv')
embedded nul(s) found in input
BrFlights2 %>%
mutate(Partida.Atraso = (Partida.Real - Partida.Prevista)) %>% 
mutate(Chegada.Atraso = (Chegada.Real - Chegada.Prevista)) %>% 
mutate(Distancia = (sqrt((LatOrig - LatDest)^2 + (LongOrig - LongDest)^2))) %>% 
mutate(TempoViagem.Real = (Chegada.Real - Partida.Real)) -> tabela
<U+393C><U+3E31>-<U+393C><U+3E32> not meaningful for factors<U+393C><U+3E31>-<U+393C><U+3E32> not meaningful for factors<U+393C><U+3E31>-<U+393C><U+3E32> not meaningful for factors
tabela

Visualizando gráficos lado a lado

#exibir duas linhas e duas colunas
par(mfrow=c(2,2))
boxplot(airquality$Ozone~airquality$Solar.R)
boxplot(airquality$Ozone~airquality$Wind)
hist(airquality$Ozone)
hist(airquality$Wind)

Clusterizando dados, identificando proximidades

set.seed(1909)
x <- rnorm(15, mean = rep(1:3, each = 5), sd = 0.2)
y <- rnorm(15, mean = rep(c(1,2), each = 5), 0.2)
plot(x, y, col = 'blue', pch = 8, cex = 1)
text(x + 0.05, y + 0.05, labels = as.character(1:15))

df <- data.frame(x, y)
nclusters <- 3
modelo <- kmeans(x = df, centers = nclusters, iter.max = 5)
plot(x,y,col= modelo$cluster, pch = 19, cex=2);
points(modelo$centers, col=1:nclusters, pch = 3, cex=3, lwd = 2)

Clusterizando 3 dimensões

set.seed(1909)
velocidade <- rnorm(15, mean = rep(1:3, each = 5), sd = 0.2)
vento <- rnorm(15, mean = rep(c(1,2), each = 5), 0.2)
altura <- rnorm(15, mean = rep(c(1,2), each = 5), 0.2)
df <- data.frame(velocidade, vento, altura)
nclusters <- 4
modelo <- kmeans(x = df, centers = nclusters, iter.max = 5)
plot(df,col= modelo$cluster, pch = 19, cex=2);
points(modelo$centers, col=1:nclusters, pch = 3, cex=3, lwd = 2)

Cluster com plotly

set.seed(1909)
x <- rnorm(15, mean = rep(1:3, each = 5), sd = 0.2)
y <- rnorm(15, mean = rep(c(1,2), each = 5), 0.2)
plot(x, y, col = 'blue', pch = 8, cex = 1)
text(x + 0.05, y + 0.05, labels = as.character(1:15))

df <- data.frame(x, y)
nclusters <- 3
modelo <- kmeans(x = df, centers = nclusters, iter.max = 5)
plot_ly(df,
        x = ~x, 
        y = ~y,
        type = 'scatter', mode ='markers',color = modelo$cluster)

Cluster 3D com plotly

set.seed(1909)
velocidade <- rnorm(15, mean = rep(1:50, each = 5), sd = 0.2)
vento <- rnorm(15, mean = rep(c(1,25), each = 5), 0.2)
altura <- rnorm(15, mean = rep(c(1,25), each = 5), 0.2)
df <- data.frame(velocidade, vento, altura)
nclusters <- 4
modelo <- kmeans(x = df, centers = nclusters, iter.max = 5)
plot_ly(df,
        x = ~velocidade, 
        y = ~vento,
        z= ~altura,
        type = 'scatter3d', mode ='markers',color = modelo$cluster)

Dendrograma (Clusterização hierárquica)

set.seed(1909)
x <- rnorm(15, mean = rep(1:3, each = 5), sd = 0.2)
y <- rnorm(15, mean = rep(c(1, 2), each = 5), sd = 0.2)
mydata <- data.frame(x, y)
# Distancia euclidiana
#dist(mydata[1:7,])
#Distancia de manhattan
#dist(mydata[1:7,], method = "manhattan")
modelo.hc <- hclust(dist(mydata))
plot(modelo.hc, main="Dendograma simples",xlab="Observações", sub="", ylab ="DIstancia")

Anaálise da média de ozonio diário por mês

p2 <- airquality %>% 
  mutate(mesFator = factor(Month)) %>% 
  
  filter(is.na(Ozone) == F) %>% 
  
  group_by(Day, mesFator) %>% 
  
  summarise(media=mean(Ozone)) %>% 
  ggplot(aes(Day, media, color = mesFator)) +
  geom_line(size = 1.5) +
  labs(x = "Mês", y = "Média de quantidade de ozônio")
p2

Gráfico de Violino

p <- ggplot(mtcars, aes(factor(cyl), mpg))
p + geom_violin(aes(fill = factor(am)))

Gráfico de pizza

ggplot(airquality,
  aes(x = factor(Month), fill = Wind) ) +
  geom_bar() +
  coord_polar(theta = "y") +
  scale_x_discrete("")

Gráfico de Barras

ggplot(airquality) +
  geom_bar(aes(Temp, fill=Temp))

Gráfico de barras verticais

ggplot(airquality, aes(Month, fill=Month) ) +
  geom_bar() + coord_flip()

Gráfico Densidade 2D

ggplot(airquality, aes( x=Wind, y=Temp) ) +
  geom_point( size=1 ) + geom_density2d()

Gráfico hexágonos

ggplot(airquality, aes(Wind, Temp)) +
  geom_hex( bins=30 )

Gráfico smooth, em cinza temos o grau de confiança na linha de tendencia.

ggplot(airquality, aes(Wind, Temp) ) +
  geom_point() + geom_smooth()

Mapa de calor

p3 <- airquality %>%
  group_by(Month, Day) %>%
  summarise(TemperaturaMedia = median(Temp)) %>%
  ggplot(aes(Day, Month, fill = TemperaturaMedia)) +
  geom_tile() +
  labs(x = "Dia do mês", y = "Mês") +
  scale_fill_distiller(palette = "Spectral")
p3

Mapa de correlação

airquality %>%
  cor(use="complete.obs", method = "spearman") %>%
  corrplot(type="lower", method="circle", diag=FALSE)

LS0tDQp0aXRsZTogIlByb2dyYW1hbmRvIElBIGNvbSBSIg0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KDQojIyMjIFBvcnRm82xpbw0KDQojIyMgQ2FycmVnYW5kbyBwYWNvdGVzDQoNCmBgYHtyfQ0KI2luc3RhbGwucGFja2FnZXMoJ2dncGxvdDInLCBkZXBlbmRlbmNpZXM9VFJVRSwgcmVwb3M9J2h0dHA6Ly9jcmFuLnItcHJvamVjdC5vcmcnKQ0KIw0KI2luc3RhbGwucGFja2FnZXMoImx1YnJpZGF0ZSIpDQojDQojaW5zdGFsbC5wYWNrYWdlcygncGxvdGx5JykNCiMNCiNpbnN0YWxsLnBhY2thZ2VzKCdkcGx5cicpDQojDQojaW5zdGFsbC5wYWNrYWdlcygnbGVhZmxldCcpDQojDQojaW5zdGFsbC5wYWNrYWdlcygnY29ycnBsb3QnKQ0KDQojaW5zdGFsbC5wYWNrYWdlcygncmVhZHhsJykNCg0KYGBgDQoNCmBgYHtyfQ0KbGlicmFyeShnZ3Bsb3QyKQ0KbGlicmFyeShsZWFmbGV0KQ0KbGlicmFyeShkcGx5cikNCmxpYnJhcnkocGxvdGx5KQ0KbGlicmFyeShsdWJyaWRhdGUpDQpsaWJyYXJ5KGNvcnJwbG90KQ0KbGlicmFyeShyZWFkeGwpDQpgYGANCg0KDQoNCiMjIyBDb25jZWl0b3MgZGUgdmFyaeF2ZWlzDQoNCg0KKipWZXRvcioqDQoNClRvZGEgdmFyaeF2ZWwgbm8gUiDpIHVtIHZldG9yLCB1bSB2ZXRvciBwb2RlIHZpc3RvIGNvbW8gdW0gY29uanVudG8gZGUgdmFsb3JlcyBsaW5lYXIgZSBob21vZ+puZW8uDQoNClBhcmEgYXRyaWJ1aXIgdW0gdmFsb3Ig4CB1bWEgdmFyaeF2ZWwsIHV0aWxpemFtb3MgYSBzZXRhIDwtIGluZGljYW5kbyBwYXJhIG9uZGUgZXN0YW1vcyBkaXJlY2lvbmFuZG8gbyB2YWxvci4NCg0KySBpbXBvcnRhbnRlIHNhYmVyIHRhbWLpbSwgcXVlIHBhcmEgY3JpYXIgdW0gdmV0b3IgY29tIHZhbG9yZXMsIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gYygpIHF1ZSBjb21iaW5hIG9zIHZhbG9yZXMgZW0gdW0gdmV0b3INCg0KU2VuZG8gYXNzaW0sIGFiYWl4byBlc3RhbW9zIGNyaWFuZG8gYSB2YXJp4XZlbCB2ZXRvciBlIGF0cmlidWluZG8gbyB2YWxvciAxIDUgNA0KDQpgYGB7cn0NCnZldG9yIDwtIGMoMSwgNSwgNCkNCg0KdmV0b3INCmBgYA0KDQoNCiMjIyBUaXBvcyBkZSB2YWxvcmVzDQoNCioqTnVt6XJpY29zIGUgQ2FyYWN0ZXJlcyoqDQoNCg0KTm8gUiB0ZW1wb3MgbyBjb25jZWl0byBkZSB0aXBvcywgb25kZSBjYWRhIHZhbG9yIHRlbSB1bSB0aXBvIGVzcGVj7WZpY28sIGxlbWJyYSBkYXMgYXVsYXMgZGUgbWF0ZW3hdGljYSBzb2JyZSBpbnRlaXJvcywgZGVjaW1haXMsIGV0Yz8NCg0KUGFyYSB2ZXJpZmljYXIgbyB0aXBvIGludGVycHJldGFkbyBwZWxvIFIgZGUgdW0gdmFsb3IsIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gY2xhc3ModmFsb3IpLCBvbmRlIHZhbG9yIOkgaWd1YWwgYW8gdmFsb3IgcXVlIHZvY+ogcXVlciB2ZXJpZmljYXIuDQoNCmBgYHtyfQ0KY2xhc3MoNSkNCmNsYXNzKCJPbOEgbXVuZG8iKQ0KYGBgDQoNCg0KKipSZWNvbmhlY2VuZG8gdGlwb3MgZGUgdmFyaeF2ZWlzKioNCg0KVmVqYSBxdWUgbyBSIHJlY29uaGVjZXUgbyB2YWxvciA1IGNvbW8gbvptZXJpY28gZSBvIHRleHRvICJPbOEgbXVuZG8iIGNvbW8gdW0gY29uanVudG8gZGUgY2FyYWN0ZXJlcy4NCg0KSXN0byB0YW1i6W0gc2UgYXBsaWNhIGEgdmFyaeF2ZWlzLCB2ZWphIHPzOg0KDQpgYGB7cn0NCnZhcmlhdmVsX251bWVyaWNhIDwtIGMoMSw1LDQsNykNCnZhcmlhdmVsX2NhcmFjdGVyZXMgPC0gYygiT2zhIG11bmRvIikNCg0KY2xhc3ModmFyaWF2ZWxfbnVtZXJpY2EpDQpjbGFzcyh2YXJpYXZlbF9jYXJhY3RlcmVzKQ0KYGBgDQoNCg0KVGFtYultIHBvZGVtb3MgdXNhciBhcyBmdW7n9WVzIGRpc3Bvbu12ZWlzIGVtICJpcyIgcGFyYSB2ZXJpZmljYXIgb3MgdGlwb3MsIGVzc2EgdmVyaWZpY2Hn428gcmV0b3JuYSB1bSB0aXBvIGzzZ2ljbyBwYXJhIG7zcw0KYGBge3J9DQp2YXJpYXZlbCA8LSAiNSINCmlzLm51bWVyaWModmFyaWF2ZWwpDQppcy5jaGFyYWN0ZXIodmFyaWF2ZWwpDQpgYGANCg0KDQoNCioqTPNnaWNvcyoqDQoNCk5vIFIsIHRhbWLpbSDpIHBvc3PtdmVsIGNyaWFyIHRpcG9zIGzzZ2ljb3MgKHZlcmRhZGVpcm8gb3UgZmFsc28pDQoNCmBgYHtyfQ0KbG9naWNvcyA8LSBjKFRSVUUsIEZBTFNFLCBUUlVFKQ0KbG9naWNvczIgPC0gYyhULCBGLCBUKQ0KDQpsb2dpY29zDQpsb2dpY29zMg0KDQpjbGFzcyhsb2dpY29zKQ0KYGBgDQoNCg0KVmVqYSBxdWUg6SBwb3Nz7XZlbCBhYnJldmlhciBhcyBkZWNsYXJh5/Vlcy4gDQoNCioqSW50ZWlyb3MgRXhwbGljaXRvcyoqDQoNClZvY+ogZGV2ZSB0ZXIgcGVyY2ViaWRvIHF1ZSBubyBjYXNvIGRvIHRpcG8gbnVt6XJpY28sIG8gdGlwbyBu428gZm9pIGRlY2xhcmFkbyBleHBsaWNpdGFtZW50ZSBjb21vIGludGVpcm8sIHBhcmEgZmF6ZXIgaXNzbyB2ZWphIG8gcHLzeGltbyB0cmVjaG86DQoNCmBgYHtyfQ0KaW50ZWlyb3MgPC0gYygxTCwgMkwsIDNMKQ0KDQppbnRlaXJvcw0KY2xhc3MoaW50ZWlyb3MpDQpgYGANCg0KDQojIyMgR2VyYW5kbyBzZXF16m5jaWFzDQoNCkdlcmFyIHNlcXXqbmNpYXMgbm8gUiDpIHVtYSBjb2lzYSBtdWl0byBm4WNpbCBlIGRpdmVydGlkYSEgVGVtb3MgYWxndW1hcyBmb3JtYXMgcGFyYSAgZmF6ZXIgaXNzbzoNCg0KYGBge3J9DQojR2VyYW5kbyBu+m1lcm9zIGRlIDEgYSAxMA0KMToxMA0KDQojR2VyYW5kbyBu+m1lcm9zIGRlIDEwIGEgMQ0KMTA6MQ0KDQojR2VyYW5kbyBu+m1lcm9zIGRlIDEwMCBhIDEyMA0KDQpzZXEoMTAwLCAxMjApDQoNCiNHZXJhbmRvIDEwIG76bWVyb3MgYSBwYXJ0aXIgZGUgMTAwDQoNCnNlcSgxMDAsIGxlbmd0aC5vdXQgPSAxMCkNCg0KI0dlcmFuZG8gbvptZXJvcyBkZSAxMCBhIDIwIGRlIDIgZW0gMg0KDQpzZXEuaW50KGZyb20gPSAxMCwgdG8gPSAyMCwgYnkgPSAyKQ0KDQojR2VyYW5kbyAyMCBu+m1lcm9zDQoNCnNlcV9sZW4oMjApDQoNCiNHZXJhbmRvIHVtIHZldG9yIGRvIG1lc21vIHRhbWFuaG8gcXVlIG8gdmV0b3IgcGFzc2Fkbw0KDQpzZXFfYWxvbmcoYyg3MCwgMikpDQoNCiNSZXBldGluZG8gbyBu+m1lcm8gNCA1IHZlemVzDQoNCnJlcCg0LCB0aW1lcyA9IDUpDQoNCmBgYA0KDQoqKk5BLCBOYU4sIEluZiwgLUluZiBlIE5VTEwqKg0KDQpPcyB0aXBvcyBlc3BlY2lhaXMgc+NvIHZhbG9yZXMgcXVlIHBvc3N1ZW0gdW1hIGNhcmFjdGVy7XN0aWNhIGJlbSBlc3BlY+1maWNhLg0KDQpOQSA9IE7jbyBkaXNwb27tdmVsIChOb3QgQXZhaWxhYmxlKQ0KTmFOID0gTuNvIG76bWVyaWNvIChOb3QgQSBOdW1iZXIpDQpJbmYgPSBJbmZpbml0bw0KLUluZiA9IC1JbmZpbml0bw0KTlVMTCA9IFZhemlvDQoNClBlcmNlYmEgcXVlIE5BIHBvc3N1aSB1bSB0aXBvLCBtYXMgTlVMTCBu428sIE5VTEwgcmVwcmVzZW50YSBvIG5hZGEgbm8gY2FzbyBkbyBSIGUgZGUgZGl2ZXJzYXMgbGluZ3VhZ2VucyBkZSBwcm9ncmFtYefjby4NCg0KVW0gZGV0YWxoZSDpIHF1ZSBu428g6SBwb3Nz7XZlbCBjb2xvY2FyIE5VTEwgZW0gdW0gdmV0b3IsIG91IHNlamEsIGNhc28gY3JpZW1vcyB1bSB2ZXRvciBjb20gTlVMTCwgbyBSIHJlbW92ZSBlbGUgYXV0b23hdGljYW1lbnRlDQoNCmBgYHtyfQ0KdmFsb3IubmEgPC0gTkENCnZhbG9yLm51bGwgPC0gTlVMTA0KdmFsb3IuaW5maW5pdG8gPC0gSW5mOw0KdmFsb3IubWVub3MuaW5maW5pdG8gPC0gLUluZg0KdmFsb3IubmFuIDwtIE5hTg0KDQp2ZXRvci5jb20ubnVsbCA8LSBjKDEwLDEwLDEwLE5VTEwpDQoNCnZldG9yLmNvbS5udWxsDQpgYGANCg0KDQojIyMgT3BlcmHn9WVzIGFyaXRt6XRpY2FzDQoNCk5vIFIg6SBwb3Nz7XZlbCBmYXplciBvcGVyYef1ZXMgYXJpdG3pdGljYXMgZW50cmUgb3MgdmFsb3JlcyBkaXNwb27tdmVpcywgYWJhaXhvIHRlcmVtb3MgZXhlbXBsb3MgcGFyYSBhbGd1bWFzIG9wZXJh5/VlcyBhcml0bel0aWNhcyBzaW1wbGVzOg0KYGBge3J9DQoNCiMgQWRp5+NvDQphZGljYW8gPC0gNSs1DQphZGljYW8NCg0KIyBTdWJ0cmHn428NCnN1YnRyYWNhbyA8LSA1LTUNCnN1YnRyYWNhbw0KDQojIE11bHRpcGxpY2Hn428NCm11bHRpcGxpY2FvIDwtIDUqNQ0KbXVsdGlwbGljYW8NCg0KIyBEaXZpc+NvDQpkaXZpc2FvIDwtIDUvNQ0KZGl2aXNhbw0KDQojUmFpeiBRdWFkcmFkYQ0KDQpyYWl6IDwtIHNxcnQoMTApDQpyYWl6DQoNCiNOdW1lcm8gaW1hZ2lu4XJpbw0KbnVtZXJvIDwtIDFpDQpudW1lcm8NCmBgYA0KDQoqKk9wZXJh5/VlcyBjb20gdmV0b3JlcyoqDQoNCkFzIG9wZXJh5/VlcyBhcml0bel0aWNhcyBzZSBlc3RlbmRlbSBhIHZldG9yZXMgdGFtYultLCB2ZWphIGFiYWl4byB1bSBleGVtcGxvOg0KDQpgYGB7cn0NCiMgVmV0b3IgZGUgZGV6IHBvc2nn9WVzDQp2ZXRvciA8LSBjKDE6MTApDQoNCnZldG9yICogMg0KDQojIFZlamEgcXVlIG9idGVtb3MgbyBkb2JybyBkZSBjYWRhIHZhbG9yIGRvIHZldG9yLCBpc3NvIHNlIGFwbGljYSBwYXJhIHRvZGFzIGFzIG9wZXJh5/Vlcy4NCg0KYGBgDQoNCg0KDQojIyMgVGlwb3MgYXZhbudhZG9zDQoNCioqRmF0b3JlcyoqDQoNCkF0cmF26XMgZGUgZmF0b3Jlcywg6SBwb3Nz7XZlbCBjbGFzc2lmaWNhciBkYWRvcyBwYXJhIHF1ZSBhcyBt4XF1aW5hcyBjb25zaWdhbSBwcm9jZXNzYXIgY29tIG1haXMgZmFjaWxpZGFkZS4gVmVqYSBxdWUgbm8gb3V0cHV0LCBvIFIgZXNjcmV2ZSAiTGV2ZWxzOiBGZW1pbmlubyBNYXNjdWxpbm8iIHBhcmEgaWRlbnRpZmljYXIgYXMgY2xhc3NlcyBlbmNvbnRyYWRhcy4NCmBgYHtyfQ0Kc2V4byA8LSBjKCJGZW1pbmlubyIsICJNYXNjdWxpbm8iLCJGZW1pbmlubyIsICJNYXNjdWxpbm8iLCJGZW1pbmlubyIsICJNYXNjdWxpbm8iLCJGZW1pbmlubyIsICJNYXNjdWxpbm8iLCJGZW1pbmlubyIsICJNYXNjdWxpbm8iKQ0KDQpmYXRvcmFkbyA8LSBhcy5mYWN0b3Ioc2V4byk7DQoNCmZhdG9yYWRvDQpgYGANCg0KDQoqKkxpc3RhcyoqDQoNCk5vIFIsIHRlbW9zIG8gdGlwbyBkZSBsaXN0YSBvbmRlIOkgcG9zc+12ZWwgYXJtYXplbmFyIHZldG9yZXMgY29tIHRpcG9zIGRpZmVyZW50ZXM6DQpgYGB7cn0NCg0KdjEgPC0gYygxLCAyLCAzKTsNCnYyIDwtIGMoVCwgRiwgVCk7DQp2MyA8LSBjKCJhIiwgImIiLCAiYyIpOw0KbGlzdGEgPC0gbGlzdCh2MSwgdjIsIHYzKQ0KDQpjbGFzcyhsaXN0YSkNCg0KbGlzdGENCmBgYA0KDQoNCg0KKipNYXRyaXplcyoqDQoNCk1hdHJpemVzIHPjbyB1bSBjb25qdW50byBkZSB2YWxvcmVzIGRpc3RyaWJ17WRvcyBlbSBsaW5oYXMgZSBjb2x1bmFzLiBBIHZpc3VhbGl6YefjbyBhYmFpeG8gZGV2ZSBlc2NsYXJlY2VyIG1lbGhvcjoNCmBgYHtyfQ0KbWF0cml6IDwtIG1hdHJpeChuY29sID0gNSwgbnJvdyA9IDUsIGRhdGEgPSAxOjUpDQoNCm1hdHJpeg0KYGBgDQoNClZvY+ogZGV2ZSB0ZXIgcGVyY2ViaWRvIHF1ZSB0YW1i6W0g6SBwb3Nz7XZlbCBhdHJpYnVpciB1bWEgbWF0cml6IHBhcmEgdW1hIHZhcmnhdmVsIGNvbSBlc3NlIGV4ZW1wbG8uDQoNClZhbW9zIGEgdW0gZXhlbXBsbyBkZSBvcGVyYefjbyBjb20gbWF0cml6ZXMNCmBgYHtyfQ0KbWF0cml6QSA8LSBtYXRyaXgobmNvbCA9IDUsIG5yb3cgPSA1LCBkYXRhID0gMTo1KQ0KbWF0cml6QiA8LSBtYXRyaXgobmNvbCA9IDUsIG5yb3cgPSA1LCBkYXRhID0gMTo1KQ0KDQojIEVzdGEgb3BlcmHn428gYWJhaXhvIG7jbyDpIHVtYSBtdWx0aXBsaWNh5+NvIGRlIG1hdHJpemVzLCDpIGFwZW5hcyB1bWEgbXVsdGlwbGljYefjbyBkZSB2YWxvcmVzLg0KbWF0cml6IDwtIG1hdHJpekEgKiBtYXRyaXpCDQoNCm1hdHJpeg0KYGBgDQoNClBhcmEgZmF6ZXJtb3MgdW1hIG11bHRpcGxpY2Hn4W8gZGUgbWF0cml6ZXMsIHByZWNpc2Ftb3Mgc2VndWlyIHVtYSByZWdyYTogYSBxdWFudGlkYWRlIGRlIGNvbHVuYXMgZGEgbWF0cml6IEEgZGV2ZSBzZXIgZXF1aXZhbGVudGUgYSBxdWFudGlkYWRlIGRlIGxpbmhhcyBkYSBtYXRyaXogQi4NCg0KQWJhaXhvIHVtIGV4ZW1wbG8gZGUgbXVsdGlwbGljYefjbyBkZSBtYXRyaXplczoNCmBgYHtyfQ0KbGluaGFzIDwtIDUNCmNvbHVuYXMgPC0gMTANCg0KbWF0cml6QSA8LSBtYXRyaXgobmNvbCA9IGxpbmhhcywgbnJvdyA9IGNvbHVuYXMsIGRhdGEgPSAxOjIpDQptYXRyaXpCIDwtIG1hdHJpeChuY29sID0gY29sdW5hcywgbnJvdyA9IGxpbmhhcywgZGF0YSA9IDE6MikNCg0KbWF0cml6QSAlKiUgbWF0cml6Qg0KYGBgDQoNCg0KKipGdW7n9WVzIPp0ZWlzIHBhcmEgbWF0cml6ZXMqKg0KDQpgYGB7cn0NCm1hdHJpekEgPC0gbWF0cml4KG5jb2wgPSAyLCBucm93ID0gMiwgZGF0YSA9IDE6NCkNCg0KZGltKG1hdHJpekEpICAjaW52ZXJzYSwgZXN0YSBkZXZlIHNlciBxdWFkcmFkYQ0KDQp0KG1hdHJpekEpICN0cmFuc3Bvc3RhDQoNCmRpYWcobWF0cml6QSkgI2lkZW50aWRhZGUNCg0Kc29sdmUobWF0cml6QSkgICNpbnZlcnNhLCBlc3RhIGRldmUgc2VyIHF1YWRyYWRhDQoNCm1hdHJpekEgPC0gY2JpbmQobWF0cml6QSwgYyg1LDIpKSAjQWRpY2lvbmEgY29sdW5hcyBubyBmaW0gZGEgbWF0cml6DQoNCm1hdHJpekEgI0NvbHVuYXMgYWRpY2lvbmFkYXMNCg0KbWF0cml6QSA8LSByYmluZChtYXRyaXpBLCBjKDUsMiwgMykpIA0KDQptYXRyaXpBICNMaW5oYXMgYWRpY2lvbmFkYXMNCmBgYA0KDQoNCioqRGF0YSBGcmFtZSoqDQoNCkNyaWFyIHVtIGRhdGFmcmFtZSDpIGJlbSBzaW1wbGVzLCB2ZWphOg0KYGBge3J9DQoNCnZldG9yQSA8LSBjKDEsNSw0LDcpDQp2ZXRvckIgPC0gYygiT2zhIG11bmRvIikNCg0KZGF0YWZyYW1lIDwtIGRhdGEuZnJhbWUodmV0b3JBLCB2ZXRvckIpDQoNCiMgQ29sb2NhbmRvIG5vbWVzIG5hcyBjb2x1bmFzDQoNCmNvbG5hbWVzKGRhdGFmcmFtZSkgPC0gYygiTnVt6XJpY28iLCAiVGV4dG8iKQ0KDQpkYXRhZnJhbWUNCmBgYA0KDQpPIG1haXMgbGVnYWwgZG8gZGF0YWZyYW1lLCDpIHF1ZSBjb25zZWd1aW1vcyBjb2xvY2FyIGRhZG9zIGhldGVyb2fqbmVvcywgYW8gY29udHLhcmlvIGRvcyB2ZXRvcmVzIGUgbWF0cml6ZXMuDQoNClRhbWLpbSDpIHBvc3PtdmVsIGNyaWFyIHVtIGRhdGFmcmFtZSBhIHBhcnRpciBkZSB1bWEgbGlzdGE6DQpgYGB7cn0NCmxpc3RhIDwtIGxpc3QoYygxLDIpLCBjKFQsRiksIGMoInRlc3RlIiwgInRlc3RlMiIpKQ0KDQpkYXRhZnJhbWUgPC0gZGF0YS5mcmFtZShsaXN0YSkNCg0KZGF0YWZyYW1lDQpgYGANCg0KDQoqKkRhdGFzKioNCg0KR2VyYWxtZW50ZSBvIHRyYWJhbGhvIGNvbSBkYXRhcyDpIHVtYSBkYXMgY29pc2FzIG1haXMgY29tcGxleGFzIGVtIHByb2dyYW1h5+NvLiBWYW1vcyB2ZXIgYXF1aSBhbGd1bWFzIGZ1buf1ZXMgcXVlIG8gUiBkaXNwb25pYmlsaXphIHBhcmEgbvNzOg0KYGBge3J9DQpkYXRhLnRleHRvID0gIjEzLzExLzIwMTggVCAxOToxMDowMCINCmRhdGEuZGF0ZSA9IGFzLkRhdGUoZGF0YS50ZXh0byxmb3JtYXQ9IiVkLyVtLyVZIFQgJUg6JU06JVMiLHR6PSJBbWVyaWNhL1Nhb19QYXVsbyIpDQpkYXRhLnRpbWUxID0gYXMuUE9TSVhjdChkYXRhLnRleHRvLGZvcm1hdD0iJWQvJW0vJVkgVCAlSDolTTolUyIsdHo9IkFtZXJpY2EvU2FvX1BhdWxvIikNCmRhdGEudGltZTIgPSBhcy5QT1NJWGx0KGRhdGEudGV4dG8sZm9ybWF0PSIlZC8lbS8lWSBUICVIOiVNOiVTIix0ej0iQW1lcmljYS9TYW9fUGF1bG8iKQ0KZGF0YS50aW1lMQ0KZGF0YS50aW1lMg0KZGF0YS5kYXRlIA0KYGBgDQoNCkF0cmF26XMgZG8gbel0b2RvIHVuY2xhc3MsIHBvZGVtb3MgdmVyIG8gY29udGX6ZG8gcmVhbCBkZSB1bWEgdmFyaeF2ZWwsIHN1YXMgcHJvcHJpZWRhZGVzIGUgZXRjLg0KUXVhbmRvIHBhc3NhbW9zIGRhdGEuZGF0ZSBwYXJhIGEgZnVu5+NvIHVuY2xhc3MsIG9idGVtb3MgYSBxdWFudGlkYWRlIGRlIGRpYXMgZGVzZGUgMDEvMDEvMTk3MCBhdOkgYSBkYXRhIGRhIHZhcmnhdmVsLg0KDQpgYGB7cn0NCnVuY2xhc3MoZGF0YS5kYXRlKQ0KYGBgDQoNCg0KTm8gY2FzbyBkZSB0aW1lMSBlIHRpbWUyIHZlamEgcXVlIG7jbyB0ZW1vcyBkaWZlcmVu52FzIG5vIHRleHRvLCBlbnRyZXRhbnRvIHZlamEgcXVhbmRvIGZhemVtb3MgbyB1bmNsYXNzLg0KYGBge3J9DQoNCnVuY2xhc3MoZGF0YS50aW1lMSkgI1RpbWUxDQoNCnVuY2xhc3MoZGF0YS50aW1lMikgI1RpbWUyDQpgYGANCg0KTyB1bmNsYXNzIG5vIHRpbWUxIHJldG9ybmEgYSBjb250YWdlbSBlbSBzZWd1bmRvcyBkZXNkZSAwMS8wMS8xOTcwIGF06SBhIGRhdGEgZGEgdmFyaeF2ZWwhIQ0KDQoNClBhcmEgb2J0ZXIgYSBkYXRhIGF0dWFsDQpgYGB7cn0NClN5cy5EYXRlKCkNCmBgYA0KDQoNCg0KKipMdWJyaWRhdGUqKg0KDQpMdWJyaWRhdGUg6SB1bSBwYWNvdGUgZGlzcG9uaWJpbGl6YWRvIHBhcmEgbWFuaXB1bGFyIGRhdGFzIG5vIFIuDQpQYXJhIGluc3RhbGFyIGUgY2FycmVnYXI6DQpgYGB7cn0NCiNpbnN0YWxsLnBhY2thZ2VzKCJsdWJyaWRhdGUiKQ0KI2xpYnJhcnkobHVicmlkYXRlKQ0KYGBgDQoNCg0KTyBsdWJyaWRhdGUgZm9ybmVjZSBmdW7n9WVzIHF1ZSByZXRvcm5hcuNvIGEgZGF0YSBubyBmb3JtYXRvIHNvbGljaXRhZG8gZSBhbOltIGRpc3NvIGVsZSB0cmFiYWxoYSBjb20gbyBjb25jZWl0byBkZSBkdXJh5+NvLg0KYGBge3J9DQpzZWd1bmRvcyAgPSBkc2Vjb25kcygyNjApDQptaW51dG9zICA9IGRtaW51dGVzKDI2MCkNCmFub3MgID0gZHllYXJzKDI2MCkNCg0KZHVyYXRpb24oMTAsIHVuaXRzID0gInNlY29uZHMiKQ0KDQpzZWd1bmRvcw0KbWludXRvcw0KYW5vcw0KDQojYWJhaXhvIGFzIGZ1buf1ZXMgZGUgZGF0YQ0KDQojQW5vIG1lcyBkaWENCmRhdGEgPC0geW1kKCIyMDE5MDEwMSIpDQoNCiMgRGlhIG1lcyBhbm8gaG9yYQ0KZG15X2goIjExMTAyMDE4MTAiKQ0KDQojIFJldG9ybmEgbyBkaWEgZGEgc2VtYW5hDQp3ZGF5KGRhdGEsIGxhYmVsID0gVCkNCg0KYGBgDQoNCg0KDQojIyMgRXN0cnV0dXJhcyBkZSBjb250cm9sZQ0KDQpQYXJhIHRvbWFyIGFsZ3VtYXMgZGVjaXP1ZXMgZHVyYW50ZSBhIGV4ZWN15+NvIGRlIGPzZGlnbywgbyBSIGZvcm5lY2UgYWxndW1hcyBlc3RydXR1cmFzIGRlIGNvbnRyb2xlLg0KDQpgYGB7cn0NCg0Kc291Qm9uaXRvIDwtIFRSVUUNCg0KaWYgKHNvdUJvbml0bykgew0KICBwcmludCgiRXUgU2VpIikNCn0gZWxzZSB7DQogIHByaW50KCJWaXNoIikNCn0NCg0Kc291Qm9uaXRvIDwtIEYNCmlmZWxzZShzb3VCb25pdG8sICJ2ZXJkYWRlIiwgImZhbHNvIikNCg0KYGBgDQoNCkVzdHJ1dHVyYXMgZGUgY29udHJvbGUgc+NvIG11aXRvIPp0ZWlzIHF1YW5kbyB2b2PqIHByZWNpc2EgdGVzdGFyIGFsZ3VtIHRpcG8gZGUgY29uZGnn428sIHNlIGFsZ3VtYSBjb21wcmEgZm9pIHJlYWxpemFkYSBwb3IgZXhlbXBsbywgb3Ugc2UgYWxnbyBvY29ycmV1Lg0KDQojIyMgRXN0cnV0dXJhcyBkZSByZXBldGnn428gPSBsb29wcw0KDQoNCkxvb3BzIHPjbyB1dGlsaXphZG9zIHF1YW5kbyBwcmVjaXNhbW9zIHBvciBleGVtcGxvIHJlcGV0aXIgdW0gY29uanVudG8gZGUgaW5zdHJ15/VlcyBwYXJhIGRldGVybWluYWRvcyBpdGVucy4NCmBgYHtyfQ0KaXRlbnMgPC0gYygxMCwyMCwzMCkNCg0KZm9yICh2YXJpYWJsZSBpbiBpdGVucykgew0KICBwcmludCh2YXJpYWJsZSkNCn0NCmBgYA0KDQpWZWphIHF1ZSBlc2NyZXZlbW9zIHRvZG9zIG9zIGl0ZW5zIGRvIHZldG9yIG5hIHRlbGEsIHBvZGVtb3MgdXRpbGl6YXIgcGFyYSBjb25zb2xpZGFyIGluZm9ybWHn9WVzIGUgZW5maW0sIHBhcmEgcXVhbHF1ZXIgY29uanVudG8gZGUgaW5zdHJ15/VlcyBxdWUgcHJlY2lzZSBzZSByZXBldGlyLg0KDQpWYW1vcyBtb250YXIgdW0gZGF0YWZyYW1lIGNvbSB1bSBsb29wDQoNCmBgYHtyfQ0KdmV0b3IgPC0gMToxMA0KYWN1bXVsYWRvIDwtIDANCnRhYmVsYSA8LSBkYXRhLmZyYW1lKCk7DQpmb3IgKHZhcmlhYmxlIGluIHZldG9yKSB7DQogIGFjdW11bGFkbyA8LSB2YXJpYWJsZSArIGFjdW11bGFkbw0KICAgdGFiZWxhIDwtIHJiaW5kKHRhYmVsYSwgYyh2YXJpYWJsZSwgYWN1bXVsYWRvKSkNCn0NCg0KY29sbmFtZXModGFiZWxhKSA8LSBjKCJWYWxvcjEiLCAiQWN1bXVsYWRvIikNCnRhYmVsYQ0KDQpgYGANCg0KDQoNCg0KIyMjIEZ1buf1ZXMNCg0KRnVu5/VlcyBz428gdXRpbGl6YWRhcyBxdWFuZG8gcXVlcmVtb3MgcmVhcHJvdmVpdGFyIGFsZ3VtIHRyZWNobyBkZSBj82RpZ28gZXNwZWPtZmljby4gcG9yIGV4ZW1wbG8sIGRpZ2Ftb3MgcXVlIHByZWNpc2Ftb3MgY2FsY3VsYXIgbyBlbmVzaW1vIHRlcm1vIGRlIHVtYSBQcm9ncmVzc+NvIEFyaXRt6XRpY2ENCg0KYGBge3J9DQoNCnByaW1laXJvLnRlcm1vIDwtIDENCnJhemFvIDwtIDINCg0Kb2J0ZXIudGVybW8ucGEgPC0gZnVuY3Rpb24ocHJpbWVpcm8udGVybW8sIG51bWVyby50ZXJtbywgcmF6YW8pIHsNCiAgcmV0dXJuKHByaW1laXJvLnRlcm1vICsgKG51bWVyby50ZXJtbyAtIDEpICogcmF6YW8pDQp9DQoNCm9idGVyLnRlcm1vLnBhKHByaW1laXJvLnRlcm1vLCA1MCwgcmF6YW8pDQpgYGANCg0KRW0gZnVu5/VlcywgcG9kZW1vcyByZWNlYmVyIHJldGlj6m5jaWFzIGNvbW8gcGFyYW1ldHJvLCBxdWUgc2lnbmlmaWNhIHF1ZSBwb2RlbW9zIHJlY2ViZXIgTiBwYXJhbWV0cm9zIG5hIGZ1bufjby4gVW0gZXhlbXBsbyBkZSBmdW7n428gYXNzaW0g6SBhIGZ1bufjbyBwYXN0ZS4NCmBgYHtyfQ0KDQpjb25jYXRlbmEgPC0gZnVuY3Rpb24oLi4uKSB7DQogIGMgPC0gcGFzdGUoLi4uKQ0KICBjDQp9DQoNCmNvbmNhdGVuYSgiU2VyZ2lvIiwgIlByYXRlcyIpDQpgYGANCg0KDQoNCiMjIyBBbW9zdHJhcw0KDQpObyBSIHBvc3N1aW1vcyBhIGZ1bufjbyBzYW1wbGUgcGFyYSByYW5kb21pemFyIGEgb2NvcnLqbmNpYSBkZSBkZXRlcm1pbmFkb3MgdmFsb3Jlcw0KYGBge3J9DQoNCiMgTGV0cmFzIGRlIGEgYXTpIGcNCmFtb3N0cmExIDwtIGxldHRlcnNbMTo3XQ0KDQojIExldHJhcyBkZSBBIGF06SBEDQphbW9zdHJhMiA8LSBMRVRURVJTWzE6NF0NCg0KIyBQb2RlIHJlcGV0aXIgYXMgb2NvcnLqbmNpYXMNCnNhbXBsZSh4ID0gYW1vc3RyYTEsIHNpemUgPSAyMCwgcmVwbGFjZSA9IFQpDQoNCiMgTuNvIHBvZGUgcmVwZXRpciBhcyBvY29ycupuY2lhcw0Kc2FtcGxlKHggPSBhbW9zdHJhMiwgc2l6ZSA9IDMsICByZXBsYWNlID0gRikNCmBgYA0KDQpQYXJhIGdhcmFudGlyIHF1ZSBzZW1wcmUgbyBtZXNtbyByZXN1bHRhZG8gYWNvbnRl52EsIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gc2V0LnNlZWQgY29tIHVtIHZhbG9yIGZpeG8NCmBgYHtyfQ0Kc2V0LnNlZWQoMSkNCnNhbXBsZSh4ID0gYW1vc3RyYTEsIHNpemUgPSAyMCwgcmVwbGFjZSA9IFQpDQpgYGANCg0KDQoNCiMjIyBTaW11bGHn9WVzDQoNCk8gUiBub3MgZm9ybmVjZSBhbGd1bnMgY29tYW5kb3MgcGFyYSBnZXJhciBkYWRvcyBhbGVhdPNyaW9zLCBzZW5kbyBlbGVzIGRhIGZhbe1saWEgbm9ybWFsLCBiaW5vbWlhbCBlIHVuaWZvcm1lLg0KDQpPcyBjb21hbmRvcyBkYSBmYW1pbGlhIG5vcm1hbCBwb3NzdWVtIG5vcm0gbm8gZmluYWwsIG9zIGJpbm9taWFpcyBwb3NzdWVtIGJpbm9tIGUgYXNzaW0gcG9yIGRpYW50ZS4uLg0KVmVqYSBhYmFpeG8gZXhlbXBsb3M6DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTgpICNnYXJhbnRpbmRvIHF1ZSBzZW1wcmUgc2FpcuEgbyBtZXNtbyByZXN1bHRhZG8NCg0KIyBzZCByZXByZXNlbnRhIG8gZGVzdmlvIHBhZHLjbyBkb3MgZGFkb3MNCg0Kcm5vcm0obj0xMCwgbWVhbj0wLCBzZD0xKQ0KDQpkbm9ybSh4ID0gMToxMCwgbWVhbiA9IDAsIHNkID0gMSkNCg0KcG5vcm0oIHEgPSAxOjEwLCBtZWFuID0gMCwgc2QgPSAxKQ0KDQpyYmlub20oc2l6ZSA9IDE6MTAsIHByb2IgPSBjKDAuMSwwLjEsMC4xLDAuMSwwLjEsMC4xLDEsMSwxLDEpLCBuID0gMTApDQoNCmRiaW5vbShzaXplID0gMToxMCwgcHJvYiA9IGMoMC4xLDAuMSwwLjEsMC4xLDAuMSwwLjEsMSwxLDEsMSksIHggPSAxOjEwKQ0KDQpwYmlub20ocSA9IDE6MTAsIHNpemUgPSAxOjEwLCBwcm9iID0gYygwLjEsMC4xLDAuMSwwLjEsMC4xLDAuMSwxLDEsMSwxKSkNCg0KcnBvaXMoMTAwLCA1KQ0KYGBgDQoNCiMjIyBSZXN1bW8gZG8gZGF0YXNldCBjb20gR2xpbXBzZQ0KDQpHbGltcHNlIOkgdW1hIGZ1bufjbyBxdWUgZXN04SBkZW50cm8gZG8gcGFjb3RlIGRwbHlyLiDJIG11aXRvIGludGVyZXNzYW50ZSBwb3IgcXVlIGNvbnNlZ3VpbW9zIHZlciB1bSByZXN1bW8gZG9zIGRhZG9zIGUgYW1vc3RyYXMuIFZlamEgYWJhaXhvIHBhcmEgZmljYXIgbWFpcyBjbGFybyBvIGdsaW1wc2UgY29tIG8gZGF0YXNldCBkbyBtdGNhcnMNCg0KYGBge3J9DQpnbGltcHNlKG10Y2FycykNCmBgYA0KDQoNCg0KIyMjIFBsb3RzIGLhc2ljbw0KDQpQYXJhIGZhemVyIHBsb3RzLCBvdSBncuFmaWNvcyBlbSBSIHBvZGVtb3MgdXRpbGl6YXIgYSBmdW7n428gcGxvdCgpDQpgYGB7cn0NCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAicCIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAibCIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCg0KI0hpc3RvZ3JhbWFzIHNlcnZlbSBwYXJhIGFuYWxpc2FyIGZyZXF16m5jaWFzDQpwbG90KHggPSBjYXJzJHNwZWVkLCB5ID0gY2FycyRkaXN0LCB0eXBlID0gImgiLCB4bGFiID0gIlZlbG9jaWRhZGUiLCB5bGFiID0gIkRpc3TibmNpYSIsIG1haW4gPSAiRGlzdOJuY2lhIHggVmVsb2NpZGFkZSIpDQoNCg0KcGxvdCh4ID0gY2FycyRzcGVlZCwgeSA9IGNhcnMkZGlzdCwgdHlwZSA9ICJiIiwgeGxhYiA9ICJWZWxvY2lkYWRlIiwgeWxhYiA9ICJEaXN04m5jaWEiLCBtYWluID0gIkRpc3TibmNpYSB4IFZlbG9jaWRhZGUiKQ0KDQpwbG90KHggPSBjYXJzJHNwZWVkLCB5ID0gY2FycyRkaXN0LCB0eXBlID0gIm8iLCB4bGFiID0gIlZlbG9jaWRhZGUiLCB5bGFiID0gIkRpc3TibmNpYSIsIG1haW4gPSAiRGlzdOJuY2lhIHggVmVsb2NpZGFkZSIpDQoNCnBsb3QoeCA9IGNhcnMkc3BlZWQsIHkgPSBjYXJzJGRpc3QsIHR5cGUgPSAicyIsIHhsYWIgPSAiVmVsb2NpZGFkZSIsIHlsYWIgPSAiRGlzdOJuY2lhIiwgbWFpbiA9ICJEaXN04m5jaWEgeCBWZWxvY2lkYWRlIikNCg0KI0FuYWxpc2FyIGNvcnJlbGHn428NCiNUZW5kZW5jaWENCiNEaXN0cmlidWnn428NCg0KI0JveCBwbG90IOkgdW0gc3VtbWFyeSBlbSBncuFmaWNvcw0KDQpib3hwbG90KGFpcnF1YWxpdHkpDQoNCmJveHBsb3QoYWlycXVhbGl0eSRPem9uZSwgb3V0bGluZSA9IEYpDQpgYGANCg0KIyMjIFVzYW5kbyBvdXRyYSBiaWJsaW90ZWNhLi4uDQoNClBvZGVtb3MgdXRpbGl6YXIgYSBlcXVh5+NvIGFiYWl4byBwYXJhIHBsb3RhciB1bSBncuFmaWNvIGxpbmVhcg0KJHkgPSBcYmV0YV8wICsgXGJldGFfMSArIFxlcHNpbG9uJA0KDQpPbmRlDQoNCiRcYmV0YV8wID0gMCw1JA0KDQokXGJldGFfMSA9IDIsMCQNCg0KJHhcc2ltIE4oMDsxsikkDQoNCiRcZXBzaWxvblxzaW0gTigwOzKyKSQNCg0KYGBge3J9DQojaW5zdGFsbC5wYWNrYWdlcygncGxvdGx5JykNCiNsaWJyYXJ5KHBsb3RseSkNCg0Kc2V0LnNlZWQoNSkNCnggPSBybm9ybShuPTM1MCwgbWVhbj0wLCBzZD0xKQ0KZSA9IHJub3JtKG49MzUwLCBtZWFuPTAsIHNkPTIpDQp5PTAuNSArIDIqeCArIGUNCg0KcGxvdCh4PXgsIHk9eSkNCg0KcGxvdF9seSh4PXgsIHk9eSwgdHlwZT0ic2NhdHRlciIsIG1vZGU9Im1hcmtlcnMiKQ0KYGBgDQoNCg0KDQoNCiMjIyBHZXJhbmRvIGdy4WZpY28gY29tIHBvbnRvcyBlIGxpbmhhcw0KDQpgYGB7cn0NCmFpcnF1YWxpdHkgJT4lIGZpbHRlcihNb250aCA9PSA1ICYgIWlzLm5hKE96b25lKSkgJT4lIGFycmFuZ2UoT3pvbmUpICU+JSBzZWxlY3QoT3pvbmlvID0gT3pvbmUpIC0+IG96b25pbw0KDQoNCm96b25pbyAlPiUgc3VtbWFyeSgpICU+JSBhcy5saXN0KCkgLT4gdmFsb3Jlcw0KDQpwbG90KG96b25pbyRPem9uaW8pDQoNCg0KbWluaW1vIDwtIG1pbih0ZXN0ZSRPem9uaW8pDQptYXhpbW8gPC0gbWF4KHRlc3RlJE96b25pbykNCm1lZGlhIDwtIG1lYW4odGVzdGUkT3pvbmlvKQ0KbWVkaWFuYSA8LSBtZWRpYW4odGVzdGUkT3pvbmlvKQ0KcXVhcnRpbCA8LSBxdWFudGlsZSh0ZXN0ZSRPem9uaW8pDQoNCg0KbGluZXMoYygwLCAzMCksIGMobWluaW1vLCBtaW5pbW8pLCBjb2wgPSAnYmx1ZScpDQpsaW5lcyhjKDAsIDMwKSwgYyhtYXhpbW8sIG1heGltbyksIGNvbCA9ICdibHVlJykNCmxpbmVzKGMoMCwgMzApLCBjKG1lZGlhLCBtZWRpYSksIGNvbCA9ICdibHVlJykNCmxpbmVzKGMoMCwgMzApLCBjKG1lZGlhbmEsIG1lZGlhbmEpLCBjb2wgPSAncmVkJykNCmxpbmVzKGMoMCwgMzApLCBjKDExLjAwLCAxMS4wMCksIGNvbCA9ICdibHVlJykNCmBgYA0KDQoNCiMjIyBCYWl4YW5kbyBkYWRvcyBleHRlcm5vcw0KDQpDb20gYSBmdW7n428gZG93bmxvYWQgZmlsZSBwb2RlbW9zIGJhaXhhciBhcnF1aXZvcyBkYSB3ZWIsIG5lc3RlIGNhc28gZWxlIHNlbXByZSB0cmF0YSBjb21vIHRleHRvIG9zIGRhZG9zLg0KDQoNCmBgYHtyfQ0KDQpiYWl4YXIgPC0gZnVuY3Rpb24odXJsKSB7DQogIA0KICAjQ3JpYSBhIHBhc3RhIGNhc28gbuNvIGV4aXN0YQ0KICANCiAgaWYoIWZpbGUuZXhpc3RzKCdkYXRhJykpew0KICAgIGRpci5jcmVhdGUoJ2RhdGEnKQ0KICB9DQogIA0KICBmaWxlLnVybCA9IHVybA0KICBmaWxlLmxvY2FsID0gZmlsZS5wYXRoKCcuL2RhdGEnLCBiYXNlbmFtZShmaWxlLnVybCkpDQogIGRvd25sb2FkLmZpbGUodXJsID0gZmlsZS51cmwsIGRlc3RmaWxlID0gZmlsZS5sb2NhbCAsIG1vZGU9J3diJykNCn0NCg0KYmFpeGFyKCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vZWx0aG9uZi9maWFwLW1iYS1yL21hc3Rlci9kYXRhL0NvcGFzLmNzdicpDQpiYWl4YXIoJ2h0dHBzOi8vcmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbS9lbHRob25mL2ZpYXAtbWJhLXIvbWFzdGVyL2RhdGEvQ29wYXMtUGFydGlkYXMuY3N2JykNCmJhaXhhcignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL2VsdGhvbmYvZmlhcC1tYmEtci9tYXN0ZXIvZGF0YS9Db3Bhcy1Kb2dhZG9yZXMuY3N2JykNCmJhaXhhcignaHR0cHM6Ly9naXRodWIuY29tL2VsdGhvbmYvZmlhcC1tYmEtci9yYXcvbWFzdGVyL2RhdGEvY2FtZXJhcy5iYWx0aW1vcmUueGxzeCcpDQoNCmBgYA0KDQojIyMgTGVuZG8gZGFkb3MgZGUgY3N2J3MNCg0KUGFyYSBsZXIgZGFkb3MgZGUgY3N2cyBwb2RlbW9zIHV0aWxpemFyIGEgZnVu5+NvIHJlYWQuY3N2DQoNCg0KYGBge3J9DQpjb3BhcyA8LSByZWFkLmNzdignLi9kYXRhL0NvcGFzLmNzdicsIGhlYWRlciA9IFQpDQpjb3Bhcw0KYGBgDQoNClBhcmEgbGVyIGRhZG9zIGRvIGV4Y2VsLCBwb2RlbW9zIHV0aWxpemFyIG8gcGFjb3RlIA0KDQpgYGB7cn0NCg0KZGYuY2FtZXJhcyA8LSByZWFkX3hsc3goJy4vZGF0YS9jYW1lcmFzLmJhbHRpbW9yZS54bHN4JykNCg0KaGVhZChkZi5jYW1lcmFzKQ0KYGBgDQoNCg0KDQojIyMgTWFuaXB1bGFuZG8gZXN0cnV0dXJhcyBkZSB0YWJlbGFzIGNvbSBkcGx5cg0KDQpPIHBhY290ZSBkcGx5ciBub3MgYWp1ZGEgYSBtYW5pcHVsYXIgZXN0cnV0dXJhcyBkZSB0YWJlbGFzIGRlIG1hbmVpcmEgYmFzdGFudGUgZWZpY2llbnRlLg0KDQpBYmFpeG8gdXRpbGl6YW1vcyBvIHBpcGUgcGFyYSBwYXNzYXIgbyBjb250ZfpkbyANCg0KYGBge3J9DQoNCkJyRmxpZ2h0czIgPC0gcmVhZC5jc3YoJy4vZGF0YS9CckZsaWdodHMyLmNzdicpDQoNCkJyRmxpZ2h0czIgJT4lDQptdXRhdGUoUGFydGlkYS5BdHJhc28gPSAoUGFydGlkYS5SZWFsIC0gUGFydGlkYS5QcmV2aXN0YSkpICU+JSANCm11dGF0ZShDaGVnYWRhLkF0cmFzbyA9IChDaGVnYWRhLlJlYWwgLSBDaGVnYWRhLlByZXZpc3RhKSkgJT4lIA0KbXV0YXRlKERpc3RhbmNpYSA9IChzcXJ0KChMYXRPcmlnIC0gTGF0RGVzdCleMiArIChMb25nT3JpZyAtIExvbmdEZXN0KV4yKSkpICU+JSANCm11dGF0ZShUZW1wb1ZpYWdlbS5SZWFsID0gKENoZWdhZGEuUmVhbCAtIFBhcnRpZGEuUmVhbCkpIC0+IHRhYmVsYQ0KDQp0YWJlbGENCmBgYA0KDQoNCg0KDQoNCiMjIyBWaXN1YWxpemFuZG8gZ3LhZmljb3MgbGFkbyBhIGxhZG8NCg0KYGBge3J9DQoNCiNleGliaXIgZHVhcyBsaW5oYXMgZSBkdWFzIGNvbHVuYXMNCg0KcGFyKG1mcm93PWMoMiwyKSkNCg0KYm94cGxvdChhaXJxdWFsaXR5JE96b25lfmFpcnF1YWxpdHkkU29sYXIuUikNCmJveHBsb3QoYWlycXVhbGl0eSRPem9uZX5haXJxdWFsaXR5JFdpbmQpDQpoaXN0KGFpcnF1YWxpdHkkT3pvbmUpDQpoaXN0KGFpcnF1YWxpdHkkV2luZCkNCg0KYGBgDQoNCg0KDQojIyMgQ2x1c3Rlcml6YW5kbyBkYWRvcywgaWRlbnRpZmljYW5kbyBwcm94aW1pZGFkZXMNCg0KYGBge3J9DQpzZXQuc2VlZCgxOTA5KQ0KDQp4IDwtIHJub3JtKDE1LCBtZWFuID0gcmVwKDE6MywgZWFjaCA9IDUpLCBzZCA9IDAuMikNCnkgPC0gcm5vcm0oMTUsIG1lYW4gPSByZXAoYygxLDIpLCBlYWNoID0gNSksIDAuMikNCnBsb3QoeCwgeSwgY29sID0gJ2JsdWUnLCBwY2ggPSA4LCBjZXggPSAxKQ0KdGV4dCh4ICsgMC4wNSwgeSArIDAuMDUsIGxhYmVscyA9IGFzLmNoYXJhY3RlcigxOjE1KSkNCg0KZGYgPC0gZGF0YS5mcmFtZSh4LCB5KQ0KDQpuY2x1c3RlcnMgPC0gMw0KbW9kZWxvIDwtIGttZWFucyh4ID0gZGYsIGNlbnRlcnMgPSBuY2x1c3RlcnMsIGl0ZXIubWF4ID0gNSkNCg0KDQpwbG90KHgseSxjb2w9IG1vZGVsbyRjbHVzdGVyLCBwY2ggPSAxOSwgY2V4PTIpOw0KDQpwb2ludHMobW9kZWxvJGNlbnRlcnMsIGNvbD0xOm5jbHVzdGVycywgcGNoID0gMywgY2V4PTMsIGx3ZCA9IDIpDQpgYGANCg0KDQojIyMgQ2x1c3Rlcml6YW5kbyAzIGRpbWVuc/Vlcw0KDQpgYGB7cn0NCnNldC5zZWVkKDE5MDkpDQoNCnZlbG9jaWRhZGUgPC0gcm5vcm0oMTUsIG1lYW4gPSByZXAoMTozLCBlYWNoID0gNSksIHNkID0gMC4yKQ0KdmVudG8gPC0gcm5vcm0oMTUsIG1lYW4gPSByZXAoYygxLDIpLCBlYWNoID0gNSksIDAuMikNCmFsdHVyYSA8LSBybm9ybSgxNSwgbWVhbiA9IHJlcChjKDEsMiksIGVhY2ggPSA1KSwgMC4yKQ0KDQpkZiA8LSBkYXRhLmZyYW1lKHZlbG9jaWRhZGUsIHZlbnRvLCBhbHR1cmEpDQoNCm5jbHVzdGVycyA8LSA0DQptb2RlbG8gPC0ga21lYW5zKHggPSBkZiwgY2VudGVycyA9IG5jbHVzdGVycywgaXRlci5tYXggPSA1KQ0KDQoNCnBsb3QoZGYsY29sPSBtb2RlbG8kY2x1c3RlciwgcGNoID0gMTksIGNleD0yKTsNCg0KI1BvbnRvcyBhcGVuYXMgZnVuY2lvbmEgZW0gcGxvdCD6bmljby4NCnBvaW50cyhtb2RlbG8kY2VudGVycywgY29sPTE6bmNsdXN0ZXJzLCBwY2ggPSAzLCBjZXg9MywgbHdkID0gMikNCmBgYA0KDQojIyMgQ2x1c3RlciBjb20gcGxvdGx5DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTkwOSkNCg0KeCA8LSBybm9ybSgxNSwgbWVhbiA9IHJlcCgxOjMsIGVhY2ggPSA1KSwgc2QgPSAwLjIpDQp5IDwtIHJub3JtKDE1LCBtZWFuID0gcmVwKGMoMSwyKSwgZWFjaCA9IDUpLCAwLjIpDQpwbG90KHgsIHksIGNvbCA9ICdibHVlJywgcGNoID0gOCwgY2V4ID0gMSkNCnRleHQoeCArIDAuMDUsIHkgKyAwLjA1LCBsYWJlbHMgPSBhcy5jaGFyYWN0ZXIoMToxNSkpDQoNCmRmIDwtIGRhdGEuZnJhbWUoeCwgeSkNCg0KbmNsdXN0ZXJzIDwtIDMNCm1vZGVsbyA8LSBrbWVhbnMoeCA9IGRmLCBjZW50ZXJzID0gbmNsdXN0ZXJzLCBpdGVyLm1heCA9IDUpDQoNCg0KcGxvdF9seShkZiwNCiAgICAgICAgeCA9IH54LCANCiAgICAgICAgeSA9IH55LA0KICAgICAgICB0eXBlID0gJ3NjYXR0ZXInLCBtb2RlID0nbWFya2VycycsY29sb3IgPSBtb2RlbG8kY2x1c3RlcikNCmBgYA0KDQojIyMgQ2x1c3RlciAzRCBjb20gcGxvdGx5DQoNCmBgYHtyfQ0Kc2V0LnNlZWQoMTkwOSkNCg0KdmVsb2NpZGFkZSA8LSBybm9ybSgxNSwgbWVhbiA9IHJlcCgxOjUwLCBlYWNoID0gNSksIHNkID0gMC4yKQ0KdmVudG8gPC0gcm5vcm0oMTUsIG1lYW4gPSByZXAoYygxLDI1KSwgZWFjaCA9IDUpLCAwLjIpDQphbHR1cmEgPC0gcm5vcm0oMTUsIG1lYW4gPSByZXAoYygxLDI1KSwgZWFjaCA9IDUpLCAwLjIpDQoNCmRmIDwtIGRhdGEuZnJhbWUodmVsb2NpZGFkZSwgdmVudG8sIGFsdHVyYSkNCg0KbmNsdXN0ZXJzIDwtIDQNCm1vZGVsbyA8LSBrbWVhbnMoeCA9IGRmLCBjZW50ZXJzID0gbmNsdXN0ZXJzLCBpdGVyLm1heCA9IDUpDQoNCg0KcGxvdF9seShkZiwNCiAgICAgICAgeCA9IH52ZWxvY2lkYWRlLCANCiAgICAgICAgeSA9IH52ZW50bywNCiAgICAgICAgej0gfmFsdHVyYSwNCiAgICAgICAgdHlwZSA9ICdzY2F0dGVyM2QnLCBtb2RlID0nbWFya2VycycsY29sb3IgPSBtb2RlbG8kY2x1c3RlcikNCmBgYA0KDQoNCiMjIyBEZW5kcm9ncmFtYSAoQ2x1c3Rlcml6YefjbyBoaWVy4XJxdWljYSkNCg0KYGBge3J9DQpzZXQuc2VlZCgxOTA5KQ0KeCA8LSBybm9ybSgxNSwgbWVhbiA9IHJlcCgxOjMsIGVhY2ggPSA1KSwgc2QgPSAwLjIpDQp5IDwtIHJub3JtKDE1LCBtZWFuID0gcmVwKGMoMSwgMiksIGVhY2ggPSA1KSwgc2QgPSAwLjIpDQpteWRhdGEgPC0gZGF0YS5mcmFtZSh4LCB5KQ0KDQojIERpc3RhbmNpYSBldWNsaWRpYW5hDQojZGlzdChteWRhdGFbMTo3LF0pDQojRGlzdGFuY2lhIGRlIG1hbmhhdHRhbg0KI2Rpc3QobXlkYXRhWzE6NyxdLCBtZXRob2QgPSAibWFuaGF0dGFuIikNCg0KbW9kZWxvLmhjIDwtIGhjbHVzdChkaXN0KG15ZGF0YSkpDQoNCnBsb3QobW9kZWxvLmhjLCBtYWluPSJEZW5kb2dyYW1hIHNpbXBsZXMiLHhsYWI9Ik9ic2VydmHn9WVzIiwgc3ViPSIiLCB5bGFiID0iRElzdGFuY2lhIikNCmBgYA0KDQoNCiMjIyBBbmHhbGlzZSBkYSBt6WRpYSBkZSBvem9uaW8gZGnhcmlvIHBvciBt6nMNCg0KYGBge3J9DQoNCg0KcDIgPC0gYWlycXVhbGl0eSAlPiUgDQogIG11dGF0ZShtZXNGYXRvciA9IGZhY3RvcihNb250aCkpICU+JSANCiAgDQogIGZpbHRlcihpcy5uYShPem9uZSkgPT0gRikgJT4lIA0KICANCiAgZ3JvdXBfYnkoRGF5LCBtZXNGYXRvcikgJT4lIA0KICANCiAgc3VtbWFyaXNlKG1lZGlhPW1lYW4oT3pvbmUpKSAlPiUgDQoNCiAgZ2dwbG90KGFlcyhEYXksIG1lZGlhLCBjb2xvciA9IG1lc0ZhdG9yKSkgKw0KDQogIGdlb21fbGluZShzaXplID0gMS41KSArDQoNCiAgbGFicyh4ID0gIk3qcyIsIHkgPSAiTelkaWEgZGUgcXVhbnRpZGFkZSBkZSBvevRuaW8iKQ0KDQpwMg0KDQpgYGANCg0KIyMjIEdy4WZpY28gZGUgVmlvbGlubw0KDQpgYGB7cn0NCnAgPC0gZ2dwbG90KG10Y2FycywgYWVzKGZhY3RvcihjeWwpLCBtcGcpKQ0KcCArIGdlb21fdmlvbGluKGFlcyhmaWxsID0gZmFjdG9yKGFtKSkpDQpgYGANCg0KDQojIyMgR3LhZmljbyBkZSBwaXp6YQ0KDQpgYGB7cn0NCmdncGxvdChhaXJxdWFsaXR5LA0KICBhZXMoeCA9IGZhY3RvcihNb250aCksIGZpbGwgPSBXaW5kKSApICsNCiAgZ2VvbV9iYXIoKSArDQogIGNvb3JkX3BvbGFyKHRoZXRhID0gInkiKSArDQogIHNjYWxlX3hfZGlzY3JldGUoIiIpDQpgYGANCg0KIyMjIEdy4WZpY28gZGUgQmFycmFzDQoNCmBgYHtyfQ0KZ2dwbG90KGFpcnF1YWxpdHkpICsNCiAgZ2VvbV9iYXIoYWVzKFRlbXAsIGZpbGw9VGVtcCkpDQpgYGANCg0KDQojIyMgR3LhZmljbyBkZSBiYXJyYXMgdmVydGljYWlzDQoNCg0KYGBge3J9DQpnZ3Bsb3QoYWlycXVhbGl0eSwgYWVzKE1vbnRoLCBmaWxsPU1vbnRoKSApICsNCiAgZ2VvbV9iYXIoKSArIGNvb3JkX2ZsaXAoKQ0KYGBgDQoNCiMjIyBHcuFmaWNvIERlbnNpZGFkZSAyRA0KDQpgYGB7cn0NCmdncGxvdChhaXJxdWFsaXR5LCBhZXMoIHg9V2luZCwgeT1UZW1wKSApICsNCiAgZ2VvbV9wb2ludCggc2l6ZT0xICkgKyBnZW9tX2RlbnNpdHkyZCgpDQpgYGANCg0KIyMjIEdy4WZpY28gaGV44Wdvbm9zDQoNCmBgYHtyfQ0KZ2dwbG90KGFpcnF1YWxpdHksIGFlcyhXaW5kLCBUZW1wKSkgKw0KICBnZW9tX2hleCggYmlucz0zMCApDQpgYGANCg0KDQojIyMgR3LhZmljbyBzbW9vdGgsIGVtIGNpbnphIHRlbW9zIG8gZ3JhdSBkZSBjb25maWFu52EgbmEgbGluaGEgZGUgdGVuZGVuY2lhLg0KDQpgYGB7cn0NCmdncGxvdChhaXJxdWFsaXR5LCBhZXMoV2luZCwgVGVtcCkgKSArDQogIGdlb21fcG9pbnQoKSArIGdlb21fc21vb3RoKCkNCmBgYA0KDQoNCg0KIyMjIE1hcGEgZGUgY2Fsb3INCg0KYGBge3J9DQpwMyA8LSBhaXJxdWFsaXR5ICU+JQ0KDQogIGdyb3VwX2J5KE1vbnRoLCBEYXkpICU+JQ0KDQogIHN1bW1hcmlzZShUZW1wZXJhdHVyYU1lZGlhID0gbWVkaWFuKFRlbXApKSAlPiUNCg0KICBnZ3Bsb3QoYWVzKERheSwgTW9udGgsIGZpbGwgPSBUZW1wZXJhdHVyYU1lZGlhKSkgKw0KDQogIGdlb21fdGlsZSgpICsNCg0KICBsYWJzKHggPSAiRGlhIGRvIG3qcyIsIHkgPSAiTepzIikgKw0KDQogIHNjYWxlX2ZpbGxfZGlzdGlsbGVyKHBhbGV0dGUgPSAiU3BlY3RyYWwiKQ0KDQpwMw0KYGBgDQoNCiMjIyBNYXBhIGRlIGNvcnJlbGHn428NCg0KYGBge3J9DQphaXJxdWFsaXR5ICU+JQ0KDQogIGNvcih1c2U9ImNvbXBsZXRlLm9icyIsIG1ldGhvZCA9ICJzcGVhcm1hbiIpICU+JQ0KDQogIGNvcnJwbG90KHR5cGU9Imxvd2VyIiwgbWV0aG9kPSJjaXJjbGUiLCBkaWFnPUZBTFNFKQ0KYGBgDQoNCg0KDQoNCg0K